package com.atguigu.java1;

import org.junit.Test;

import java.util.*;

/**
 * 1.Set接口的框架：
 *  |-----Collection接口：单列集合，用来储存一个一个的对象
 *          |------set接口：存储无序的，不可重复的数据。 --->高中讲的集合
 *              |-----HashSet：作为Set接口主要实现类：线程不安全：可以储存null值
 *                    |-----LinkedHashSet：作为HashSet的子类：遍历内部数据时，可以按照添加是顺序遍历
 *                                   对于频繁的遍历操作，LinkedHashSet效率高于HashSet
 *              |-----TreeSet：可以按照添加对象的指定属性，进行排序
 *
 *1.Set接口中没有额外定义新的方法，使用的都是Collection中声明过的方法
 *
 *2.要求：向set中添加的数据，其所在类一定要重写equals()和hashcode()方法
 *  要求：重写的hashCode()和hashCode()尽可能保持相同，拥有相同的散列码（哈希值）
 *  重写方法的小技巧：对象中用作equals()方法比较的Filed，都应该用来计算hashCode值
 */
public class SetTest {
    /*
    Set：储存无序的、不可重复的数据
    一、以HashSet为例说明：
    1.无序的：不等于随机性，储存的数据在底层数组中并非按照数组索引的顺序添加，而是根据数据的哈希值

    2.不可重复的：保证添加到元素按照equals()判断时，不能返回true。即：想同元素只能添加一个。

    二、添加元素的过程：一HashSet为例：
       我们HashSet中添加元素a，首先调用元素a所在类的hashCode()方法，计算a元素与b元素的hash值
       此哈希值通过某种算法算出hashSet底层数组中的存放位置(即为：索引位置)，判断数组所在的位置上是否
       有其他元素：
            如果此位置上没有其他元素，则a元素添加成功。--->情况1
            如果此位之上有其他元素b(或以链表形式存放多个元素)，则比较元素a和元素b的哈希值：
                    如果哈希值不同则a元素添加成功.--->情况2
                    如果哈希值相同，则需要调用元素a所在类的equals()方法:
                            equals()返回true，则元素a添加失败
                            equals()返回false，则元素a添加成功。--->情况3

       对于添加成功的情况2和情况3而言：元素a与已经存在的元素就以链表的方式储存
       jdk 7:元素a（新的元素）放在数组中，指向原来的元素
       jdk 8:原来的元素在数组中，指向元素a
       (7上8下)

       HashSet底层：数组+链表的结构
     */
    @Test
    public void test1(){
        Set set = new HashSet();
        set.add(123);
        set.add(123);
        set.add(456);
        set.add("AA");
        set.add("CC");
        set.add(new User("Tom",19));
        set.add(new User("Tom",19));
        set.add(129);

        Iterator iterator = set.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

    //LinkedHashSet()的使用
    //LinkedHashSet作为HashSet的子类，在添加数的同时，每个数据还维护了两个引用
    //记录了此数据的前一个数据和后一个数据。
    //优点：对于频繁的遍历操作，LinkedHashSet效率高于HashSet
    @Test
    public void test2(){
        Set set = new LinkedHashSet();
        set.add(123);
        set.add(123);
        set.add(456);
        set.add("AA");
        set.add("CC");
        set.add(new User("Tom",19));
        set.add(new User("Jon",19));
        set.add(129);

        Iterator iterator = set.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

    /*
    1.向TreeSet中添加的数据，要求是相同类的对象。
    2.两种排序方式：自然排序和定制排序

    3.自然排序中，比较两个对象是否相同的标准为：compareTo()返回0，不再是equals()方法
    4.定制排序，比较两个对象是否相同的标准为：compare()返回0，不再是equals().
     */
    @Test
    public void test3(){
        TreeSet set = new TreeSet();

        //失败：不能添加不同类的对象
//        set.add(123);
//        set.add(456);
//        set.add("AA");
//        set.add(new User("Tom",19));

        //举例一：
//        set.add(34);
//        set.add(-34);
//        set.add(43);
//        set.add(11);
//        set.add(8);

        //举例二：
        set.add(new User("Tom",56,1001));
        set.add(new User("Jerry",32,1002));
        set.add(new User("Jim",2,1003));
        set.add(new User("Mike",65,1004));
        set.add(new User("Jack",33,1005));
        set.add(new User("Jack",56,1006));

        Iterator iterator = set.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
            //由小到大遍历
        }
    }
    @Test
    public void test4(){
        //按照年龄从小到大排序
        Comparator com = new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                if (o1 instanceof User && o2 instanceof User){
                    User u1 = (User) o1;
                    User u2 = (User) o2;
                    return Integer.compare(u1.getAge(),u2.getAge());
                }else{
                    throw new RuntimeException("输入类型不匹配");
                }
            }
        };

        TreeSet set = new TreeSet(com);
        set.add(new User("Tom",19));
        set.add(new User("Jerry",32));
        set.add(new User("Jim",2));
        set.add(new User("Mike",65));
        set.add(new User("Mary",65));//无
        set.add(new User("Jack",33));
        set.add(new User("Jack",56));

        Iterator iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}
